package com.zz.fileoperatelib.filemediastore;

import android.content.ContentResolver;
import android.content.Context;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Build;
import android.provider.MediaStore;
import android.util.Log;
import android.util.Size;

import com.google.gson.Gson;
import com.zz.fileoperatelib.filemediastore.bean.FileBean;
import com.zz.fileoperatelib.filemediastore.bean.ImageBean;
import com.zz.fileoperatelib.filemediastore.bean.VideoBean;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;

/**
 * android 有两个数据库：internal.db和external.db，位置在/data/data/com.android.providers.media/databases/目录下，
 * 两个数据库结构字段都是一样的，只是存储的内容有区别
 * <p>
 * 其中internal对应的目录是system下的文件，如：/system/emui/base/media/Hotline_avatar.jpg文件
 * external对应的目录是sdcard(storage/emulated/0和外置SD卡如storage/16ED-120B的目录都在sdcard中)下的文件，如：storage/emulated/0/DCIM/Camera/20210407183331.jpeg
 * <p>
 * internal都是放的系统自带的文件，所以一般不涉及操作
 * external放的是共有目录（android11是9大共有目录，以前版本应用还能建其他目录）和每个应用的私有目录，
 * 手机启动时会通过contentProvider扫描除了每个应用私有目录外的共有目录，将里面的文件信息存储的数据库中
 * <p>
 * internal和external都是通过contentProvider进行数据库操作，每个数据库中，都按文件类型分为不同的URI便于调用，分为图片、音频、视频、文件、下载
 * <p>
 * 图片：存储在 DCIM/ 和 Pictures/ 目录中
 * Internal: MediaStore.Images.Media.INTERNAL_CONTENT_URI -> content://media/internal/images/media。
 * External: MediaStore.Images.Media.EXTERNAL_CONTENT_URI -> content://media/external/images/media。
 * 可移动存储: MediaStore.Images.Media.getContentUri        -> content://media/<volumeName>/images/media。
 * 音频：存储在 Alarms/、Audiobooks/、Music/、Notifications/、Podcasts/ 和 Ringtones/ 目录中
 * Internal: MediaStore.Audio.Media.INTERNAL_CONTENT_URI  -> content://media/internal/audio/media。
 * External: MediaStore.Audio.Media.EXTERNAL_CONTENT_URI  -> content://media/external/audio/media。
 * 可移动存储: MediaStore.Audio.Media.getContentUri         -> content://media/<volumeName>/audio/media。
 * 视频：存储在 DCIM/、Movies/ 和 Pictures/ 目录中
 * Internal: MediaStore.Video.Media.INTERNAL_CONTENT_URI  -> content://media/internal/video/media。
 * External: MediaStore.Video.Media.EXTERNAL_CONTENT_URI  -> content://media/external/video/media。
 * 可移动存储: MediaStore.Video.Media.getContentUri         -> content://media/<volumeName>/video/media。
 * 下载：
 * Internal: MediaStore.Downloads.INTERNAL_CONTENT_URI    -> content://media/internal/downloads。
 * External: MediaStore.Downloads.EXTERNAL_CONTENT_URI    -> content://media/external/downloads。
 * 可移动存储: MediaStore.Downloads.getContentUri           -> content://media/<volumeName>/downloads。
 * 文件：包括图片、文件、视频、音乐等多媒体文件，包括非多媒体文件，涉及所有公共目录
 * MediaStore. Files.Media.getContentUri                  -> content://media/<volumeName>/file。
 * <p>
 * <p>
 * <p>
 * <p>
 * 数据库字段:
 * INTERNAL_CONTENT_URI; //内部库URI
 * EXTERNAL_CONTENT_URI;//外部库URI
 * CONTENT_TYPE;//内容提供者类型
 * DEFAULT_SORT_ORDER;//排序方式
 * <p>
 * MediaStore.Files没有EXTERNAL_CONTENT_URI，所以只能用getContentUri()自行获取
 * 这个不难理解，以MediaStore.Images.Media为例，其URI有三种写法：
 * Uri uri1 = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
 * Uri uri2 = MediaStore.Images.Media.getContentUri("external");
 * Uri uri3 = Uri.parse("content://media/external/images/media");
 */

public class FileMediaStore {

    private Context mContext;

    public void start(Context context) {
        mContext = context;

        contentResolverExample();


        new ImageTask().execute(context.getContentResolver());
        new VideoTask().execute(context.getContentResolver());
        new FileTask().execute(context.getContentResolver());
    }

    /**
     * 查询示例
     */
    private void contentResolverExample() {
        /**
         * uri可以是音频、视频、图片、文件等的uri，必须选一个
         * MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
         * MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
         * MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
         * MediaStore.Files.getContentUri("external"); external数据库中所有文件
         */
        Uri uri = null;
        /**
         * 需要返回的列，数据库的表中有很多的属性，需要返回那些列的属性值，就填入哪个，数据库中有所有属性的列名
         * 如图片有长宽，但是音频文件没有，只要是数据库中有得都可以添加，如果是null，则返回所有列属性
         */
        String[] projection = {
                MediaStore.Images.Media._ID,
                MediaStore.Images.Media.DATA,
                MediaStore.Video.Media.MIME_TYPE,
                MediaStore.Files.FileColumns.MIME_TYPE,
                MediaStore.Files.FileColumns.SIZE,
                MediaStore.Files.FileColumns.TITLE};
        /**
         * 筛选条件，筛选参数，要搭配使用，例如：
         * “mime_type”是数据库中的一个列的字段，不同的文件用不同的变量表示，
         * 当存入txt时，用MediaStore.Files.FileColumns.MIME_TYPE存入"text/html"
         * 当存入mp4时，用MediaStore.Video.Media.MIME_TYPES属性存入"video/mp4"；实际上这两个不同类下的MIMI_TYPES，都是“mime_type”
         * 但不是所有存入的数据都一定会设置这个类型
         *
         * 一些能通过mime_type查询出来的文档 .doc .pdf .txt .apk 查询方式
         *
         * 一些不能通过mime_type查询出来的文档 .docx .xls .xlsx .rar 查询方式
         */

        //通过mime_type查询 txt pdf等
        String selection = "mime_type = ? or mime_type = ? or mime_type = ? or mime_type = ? ";
        String[] selectionArgs = new String[]{"text/html", "application/msword", "application/pdf", "text/plain"};

        //通过mime_type, 查询mp4
        selection = "mime_type = ?";
        selectionArgs = new String[]{"video/mp4"};

        //通过mime_type, 查询音频
        selection = "mime_type = ? or mime_type = ?";
        selectionArgs = new String[]{"audio/mpeg", "audio/ogg"};

        //通过mime_type, 查询图片
        selection = "mime_type = ?";
        selectionArgs = new String[]{"image/png"};

        //有些不好通过mime_type查询的，可以通过文件后缀名查询
        selection = "(" + MediaStore.Files.FileColumns.DATA + " LIKE '%.xls'" +
                " or " + MediaStore.Files.FileColumns.DATA + " LIKE '%.docx'" +
                " or " + MediaStore.Files.FileColumns.DATA + " LIKE '%.apk'" +
                " or " + MediaStore.Files.FileColumns.DATA + " LIKE '%.xlsx'" +
                " or " + MediaStore.Files.FileColumns.DATA + " LIKE '%.rar'" + ")";
        selectionArgs = null;

        /**
         * 返回数据的排序
         */
        String sortOrder = null;
        Cursor cursor = mContext.getContentResolver().query(
                uri,
                projection,
                selection,
                selectionArgs,
                sortOrder);
    }

    //查询所有公共目录图片
    private class ImageTask extends AsyncTask<ContentResolver, Void, List<ImageBean>> {

        @Override
        protected List<ImageBean> doInBackground(ContentResolver... params) {
            ContentResolver contentResolver = params[0];
            Uri externalImageContentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
            //图片的uri有三种获取方式：
            // Uri uri1 = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
            // Uri uri2 = MediaStore.Images.Media.getContentUri("external");
            // Uri uri3 = Uri.parse("content://media/external/images/media");
            Cursor cursor = contentResolver.query(
                    externalImageContentUri,
                    null,
                    null,
                    null,
                    null);
            List<ImageBean> taskList = new ArrayList<>();
            while (cursor.moveToNext()) {
                ImageBean imageBean = new ImageBean();
                int id = cursor.getInt(cursor.getColumnIndex(MediaStore.Images.Media._ID));
                String path = cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media.DATA));
                String name = cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media.DISPLAY_NAME));
                long size = cursor.getLong(cursor.getColumnIndex(MediaStore.Images.Media.SIZE));
                long duration = cursor.getLong(cursor.getColumnIndex(MediaStore.Images.Media.DURATION));
//                Uri uri = Uri.withAppendedPath(externalImageContentUri, "" + id);
                Uri uri = UriFilePathUtil.getImageContentUri(mContext, new File(path));
                imageBean.setId(id);
                imageBean.setPath(path);
                imageBean.setName(name);
                imageBean.setSize(size);
                imageBean.setDuration(duration);
                imageBean.setUri(uri);
                taskList.add(imageBean);
            }
            cursor.close();
            return taskList;
        }

        @Override
        protected void onPostExecute(List<ImageBean> taskList) {
            Gson gson = new Gson();
            String s = gson.toJson(taskList);
            Log.e("imageList:", s);//直接转json，uri获取到了，但是日志不显示
            for (ImageBean imageBean : taskList) {
//                System.out.println(imageBean.toString());
            }

            /**
             * 结果：
             I/System.out: ImageBean{id=36, path='/storage/emulated/0/DCIM/Camera/IMG_20210114_122444.jpg', name='IMG_20210114_122444.jpg', uri=content://media/external/images/media/36, size=2790231, duration=0}
             I/System.out: ImageBean{id=37, path='/storage/emulated/0/DCIM/Camera/IMG_20210114_190038.jpg', name='IMG_20210114_190038.jpg', uri=content://media/external/images/media/37, size=3329828, duration=0}
             I/System.out: ImageBean{id=39, path='/storage/emulated/0/Huawei/MagazineUnlock/magazine-unlock-06-2.3.6662-72F9E66782C90AA70BC3B217D109AC82.jpg', name='magazine-unlock-06-2.3.6662-72F9E66782C90AA70BC3B217D109AC82.jpg', uri=content://media/external/images/media/39, size=66192, duration=0}
             */
        }
    }


    //查询所有公共目录视频
    private class VideoTask extends AsyncTask<ContentResolver, Void, List<VideoBean>> {

        @Override
        protected List<VideoBean> doInBackground(ContentResolver... params) {
            // Uri uri1 = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
            // Uri uri2 = MediaStore.Video.Media.getContentUri("external");
            // Uri uri3 = Uri.parse("content://media/external/video/media");
            ContentResolver contentResolver = params[0];
            Uri externalContentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
            Cursor cursor = contentResolver.query(
                    externalContentUri,
                    null,
                    null,
                    null,
                    null);
            List<VideoBean> taskList = new ArrayList<>();
            while (cursor.moveToNext()) {
                VideoBean videoBean = new VideoBean();
                int id = cursor.getInt(cursor.getColumnIndex(MediaStore.Video.Media._ID));
                String path = cursor.getString(cursor.getColumnIndex(MediaStore.Video.Media.DATA));
                String name = cursor.getString(cursor.getColumnIndex(MediaStore.Video.Media.DISPLAY_NAME));
                long size = cursor.getLong(cursor.getColumnIndex(MediaStore.Video.Media.SIZE));
                long duration = cursor.getLong(cursor.getColumnIndex(MediaStore.Video.Media.DURATION));
                Uri uri = Uri.withAppendedPath(externalContentUri, "" + id);
                Bitmap bitmap = null;
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
                    try {
                        Size size1 = new Size(300, 300);
                        bitmap = contentResolver.loadThumbnail(uri, size1, null);
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                } else {
                    String thumbPath = cursor.getString(cursor.getColumnIndex(MediaStore.Video.Thumbnails.DATA));
                    bitmap = BitmapFactory.decodeFile(thumbPath);
                }
                videoBean.setId(id);
                videoBean.setPath(path);
                videoBean.setName(name);
                videoBean.setSize(size);
                videoBean.setDuration(duration);
                videoBean.setUri(uri);
                videoBean.setBitmap(bitmap);
                taskList.add(videoBean);
            }
            cursor.close();
            return taskList;
        }

        @Override
        protected void onPostExecute(List<VideoBean> taskList) {
            Gson gson = new Gson();
            String s = gson.toJson(taskList);
            Log.e("videoList:", s);
            for (VideoBean videoBean : taskList) {
//                System.out.println(videoBean.toString());
            }
        }
    }

    //查询所有文件，包含多媒体的音视频，也包含apk txt等其他文件
    private class FileTask extends AsyncTask<ContentResolver, Void, List<FileBean>> {

        @Override
        protected List<FileBean> doInBackground(ContentResolver... params) {

            if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.Q) {
                Set<String> externalVolumeNames = MediaStore.getExternalVolumeNames(mContext);
                for (String externalVolumeName : externalVolumeNames) {
                    Uri mediaUri = MediaStore.Files.getContentUri(externalVolumeName);
                }
            }

            Uri external = MediaStore.Files.getContentUri("external");

            ContentResolver contentResolver = params[0];
            Cursor cursor = contentResolver.query(
                    external,
                    null,
                    null,
                    null,
                    null);
            List<FileBean> taskList = new ArrayList<>();
            while (cursor.moveToNext()) {
                FileBean fileBean = new FileBean();
                int id = cursor.getInt(cursor.getColumnIndex(MediaStore.Files.FileColumns._ID));
                String path = cursor.getString(cursor.getColumnIndex(MediaStore.Files.FileColumns.DATA));
                String name = cursor.getString(cursor.getColumnIndex(MediaStore.Files.FileColumns.DISPLAY_NAME));
                long size = cursor.getLong(cursor.getColumnIndex(MediaStore.Files.FileColumns.SIZE));
                long duration = cursor.getLong(cursor.getColumnIndex(MediaStore.Files.FileColumns.DURATION));

                fileBean.setId(id);
                fileBean.setPath(path);
                fileBean.setName(name);
                fileBean.setSize(size);
                fileBean.setDuration(duration);
                taskList.add(fileBean);
            }
            cursor.close();

            return taskList;
        }

        @Override
        protected void onPostExecute(List<FileBean> taskList) {

            Gson gson = new Gson();
            String s = gson.toJson(taskList);
            Log.e("fileList:", s);
            for (FileBean fileBean : taskList) {
//                System.out.println(fileBean.toString());
            }
        }
    }
}
